Conversation
- 插件侧新增 hotkey_match.h 纯函数:字母大小写折叠 + US 布局 base/shifted 视为同一物理键 (实测 fcitx 的 Key::normalize 对符号键只改 states 不改 sym,所以注册 ';' 永远匹配不到到达的 ':')。 21 条断言的 hotkey_match_contract 覆盖 Ctrl+Shift+; / Ctrl+; 不误触发 / 字母 / 裸修饰键。 - 取消「裸修饰键一律拒绝注册」:改由插件保证不吞修饰键(shouldConsume), 按住修饰键当热键期间若按下其它键则判定组合键并放弃触发。 - 录制器支持录裸修饰键(跨帧看 Modifiers:按住→无其它键→松开),记为 LeftControl 等。 - 新增 /proc 时间戳比较:安装包替换 libopenless.so 后,若插件比运行中的 fcitx5 新, 启动时自动 fcitx5 -r,否则新匹配规则不会生效。 - 诊断日志:命中与「修饰位一致但键不同」的近似未命中(限速 1 次/秒)。 验证:cargo test 全绿;ctest 2/2(input_target_contract + hotkey_match_contract); deb 内 libopenless.so 与新构建 sha256 一致(66d534f0…)。
…包 postinst 改 D-Bus 重载 - 胶囊:录音/思考不再画红/黑外圈(用户报「语音输入弹窗有一个红边」), 改成 Tauri 的「1px 中性描边 + 随音量放大 1.8%」;中心声波/流体圆点保留。 两条新测试锁死:录音相位不得出现偏红涂色、GPU 回调数固定 1/1/0。 - 风格直达快捷键:草稿行选择器曾把 draft_pack 当行号下发 StyleHotkeyRepack, 会把已有行的包改掉,且 StyleHotkeyDraftPack 从未构造(编译告警)。 新增 style_pack_pick_action(row: Option<usize>, next) + 测试。 - popup_layer:去掉不必要的 unsafe 与未被使用的 FrameCallback 别名。 - 打包脚本:postinst/postrm 不再 `fcitx5 -r`(会替换 daemon 并前台常驻、装包卡 5s), 改用 D-Bus controller Restart(实测 0.002s 返回)。
…ze 语义只比 ctrl/alt/shift/super;近失日志降到 Info 并加可开关逐键 trace;宿主逐项记录注册的 (sym,states)
…istener 变 Option)
Linux egui 的发布此前是一条从没被调用、也从没跑成功过的独立工作流: fork 里 dispatch 时它带了一个不以 v 开头的 release_tag,在第 8 步 (依赖安装 + fcitx5 插件构建 + 全量测试之后)报 "release_tag must name an existing v* release",白烧 4.5 分钟 runner。 - release-tauri.yml 变成唯一一条发版流水线,按 tag 后缀决定构建哪些平台: v*-tauri → macOS/Windows 的 Tauri 包;v*-egui → Linux deb/rpm(egui 原生宿主, 通过 workflow_call 复用 release-linux-egui.yml);手动 dispatch → 两侧都构建。 - 新增 bundle-all-artifacts:把本次 run 的全部 artifact 收成一个 OpenLess-<tag>-all-artifacts.zip(zip 名自带 -tauri/-egui 后缀), 根目录附覆盖全部文件的 SHA256SUMS,tag 推送时挂到同一个 release。 与 build job 同一套渠道判定,beta release 不会被这个只挂 zip 的 job 升格。 - release-linux-egui.yml:tag 校验提到编译之前(几秒出结论);release target 从「release 必须先存在」改为「tag 必须存在」,让 -egui 这个新命名空间 首次推送时能自己建 release;版本推导先剥 -egui(-tauri 仅作历史兼容, 保持 release 契约测试要求的写法);首次为 -egui tag 建 release 时正确标 prerelease。
…引擎占用时释放(pinyin QuickPhraseKey,带备份)
实测 run 35120587777:22.04 上冷缓存重编 libspa 0.10.1 直接编译失败 (spa_video_info_raw has no field named flags / missing spa_meta_first), 整条发布流程卡在第 8 步。ci.yml 的 linux-core-contract 早就因为同一个原因 换到 ubuntu-24.04 并留了注释,这条工作流从没跑过所以一直没跟上。 注意:deb/rpm 的 glibc 基线随之抬高到 24.04(glibc 2.39);若需要覆盖 22.04 用户,得在依赖层解决 libspa/PipeWire 版本,而不是换 runner。
… Linux egui)
按用户拍板的方案 B 收口 tag 约定:v<version>-egui(例 v2.0.0-Beta.1-egui)
一次推送 → 同一个 run 里四平台并发构建 → 所有产物挂同一个 Release
→ 末尾 bundle-all-artifacts 打成 OpenLess-<tag>-all-artifacts.zip。
- 后缀不再是平台分发开关:-egui tag 下 build(Tauri 三腿)与
release-linux-egui(workflow_call,tag 由编排层传入)都跑,zip job needs 全四者。
- build 里所有 release 相关步骤(签名可用性检查、release body prelude、
Create/update release)从「仅 -tauri」放宽到任何 v* tag,否则 -egui 发布时
dmg/msi/exe 只进 artifacts、不会挂到 Release。
- 历史 v*-tauri tag 兼容保留:仍只跑 Tauri 三平台(旧行为),文件头注释写清
两者关系与迁移注意(Cask URL/README/bump-version.sh/android-apk.yml)。
- Linux 产物命名统一带 egui 标识:deb/rpm 已是
OpenLess-Linux-egui-<ver>-<arch>(脚本原有),校验和文件改名 SHA256SUMS-egui,
避免与其它平台/聚合层那份混淆;版本串仍由传入 tag 推导(剥 -egui)。
- update-homebrew-cask 保持仅 -tauri:cask 下载 URL 写死 v#{version}-tauri,
迁移到 -egui 前不能动,已作为待办写进文件头注释。
…rl+Shift+; 匹配「Shift 折进符号」
三个实测问题(-40 真机反馈):
1. 点关闭键没反应:winit 在原生 Wayland 上 `set_visible` 是空实现
(winit-0.30 wayland/window/mod.rs「Not possible on Wayland」),
所以 -40 的 `Visible(false)` 等于什么都没做。最小化虽受支持,但最小化的
surface 拿不到 frame callback → eframe 的 update() 停摆 → 热键、托盘、
单实例唤起全部失效(实测心跳停、按热键无反应、重启也拉不回来)。
改为 Wayland 上隐藏 = 临时放开最小内尺寸 + 塌缩到 1x1 并保持映射:
窗口看不见了,事件循环照常跑(实测隐藏后 recording=true,热键仍生效;
再次启动能把窗口按原尺寸恢复)。X11 仍走真 unmap。
2. 事件泵保活必须用真线程:tokio 运行时是 current-thread,spawn 的任务只在
别处 block_on 时才推进,当后台泵用等于没保活。
3. Ctrl+Shift+; 到达插件时是 sym=0x3a(':') 且 states 里【没有 Shift 位】
(trace 实测;字母如 Ctrl+Shift+S 则是 sym=0x53 states=0x05)。注册值
0x3b/0x05 因此永远匹配不上。匹配规则改为:符号相同则严格比修饰位;符号
成 base/shifted 对时,只有注册值本身带 Shift 才接受、并忽略事件里的
Shift 位(Ctrl+; 与 Ctrl+Shift+; 双向仍可区分)。近失日志同步放宽到
「除 Shift 外的修饰位一致」,否则这类失败永远没有日志。
…聚合 job needs: build 会让 Linux 腿等 macOS/Windows 编完才启动,那不是四平台并发。 去掉它之后两个 job 可能同时建同一个 release,所以: - release-linux-egui.yml 新增 attach_release 输入(默认 true 保持单独 dispatch 行为) - 编排层传 attach_release: false,Linux 资产改由 bundle-all-artifacts(needs 四者、 最后一个 job)统一挂到 release,顺带和 zip 一起写,写入点唯一。 bundle job 里 Linux 资产那步用 hashFiles 守卫:egui 腿失败时不会让整步失败、 也不会把 zip 一起拖下水(zip 自己有 test -s 硬门禁)。
- bundle-all-artifacts 只下载 openless-linux-egui-x86_64 这一个 artifact, zip 根部就是打包脚本的原始文件名(.deb/.rpm/SHA256SUMS),不再塞 dmg/msi/exe, 也不再另造一层汇总校验和——打包脚本自带的 SHA256SUMS 就是权威。 - Linux 校验和文件命名改回 SHA256SUMS(撤销上一轮的 SHA256SUMS-egui)。 - needs 仍为 [build, release-linux-egui]:它仍是 Linux 资产的唯一 release 写入点 (egui job 保持 attach_release: false)。 - ubuntu-24.04 的分发基线写进注释:glibc ≥ 2.39,支持范围 Ubuntu 24.04+, 22.04 / Debian 12 不在支持范围内(用户已确认,防止被改回去)。 - Homebrew、Cask、README、bump-version.sh、android-apk.yml、macOS/Windows 构建步骤均未动。
…键消费与弹窗拉起一起失效) - 有托盘:最小化 → 与关闭键同一条 hide 路径(Wayland 塌缩隐藏,事件循环继续跑) - 无托盘:保持真正的窗口管理器最小化,否则窗口找不回来 - 新增 minimize_action() 决策函数 + 测试锁死该语义
a_per_user_copy_only_shadows_when_the_package_has_the_addon 之前直接断言 /usr/lib/x86_64-linux-gnu/fcitx5/libopenless.so 存在:装了 deb 的开发机绿, 干净的 CI runner 上 is_file()=false → 该断言必挂,于是 Linux 发布腿在第 8 步 「Verify framework-independent Linux contract」失败,后续 upload/checksums 与聚合 zip job 级联失败。 改为 tempfile 自建 per-user 文件,覆盖「无文件」与「有文件 + 包内有 addon」两个 分支,并保留「无包内 addon 时不 shadow」的反例断言。用 unshare + tmpfs 隐藏系统 插件目录后该测试仍通过,证明不再依赖宿主文件系统。
已实测证伪「拼音的 QuickPhraseKey=semicolon 会吃掉 Ctrl+Shift+;」:
fcitx 的 Key::check 要求修饰位精确相等(semicolon 是 states=0,而
Ctrl+Shift+; 到达时是 states=Ctrl),两者本就能共存。用户真机验证:
保持 QuickPhraseKey=semicolon 时按 Ctrl+Shift+; 面板照常弹出。
- settings.rs: 去掉 apply_hotkeys 里对 release_engine_key_conflict 的调用
- fcitx5.rs: 删除 release_engine_key_conflict{,_in}、release_engine_reserved_key、
engine_reserved_keys、fcitx_key_aliases、fcitx_punctuation_name、
reload_addon_config 及 4 个相关单元测试(-259 行)
- tests/fcitx5_config_contract.rs: 新增不变量契约,断言宿主源码里不出现
输入法配置目录与引擎保留键;已用注入违规验证它非空转
- 真机 A/B:旧二进制会把临时 HOME 的 QuickPhraseKey 清空并留日志,
新二进制字节不变、0 条日志,且启动路径确实跑过(有热键注册日志)
冲突只出现在 openless-all/app/linux-egui/src/main.rs(4 处),且都是官方对这版 monolith 的 provider 编辑器 / remote_ui 做增量改动、而本分支 91 个提交已把这两个 子系统搬进 ui/frontend/*(改由 tr_l10n + FrontendViewModel 渲染)造成的结构性冲突。 解决方式(未使用整文件 --ours/--theirs,逐块判定): - 4 处冲突保留本分支结构,丢弃 752 行已被替换的 monolith 实现(provider 渠道列表、 provider_fields_ui/save_provider_editor/clear_provider_secrets/_ui、remote_ui、secret_edit) - 官方 auto-merge 进来的语义改动全部保留:core 的 provider_rules(+194)、 provider_service、credentials、api/llm_protocol/polish/prompts、docs 基线、 linux-egui/credentials.rs 的 volcengine_service,以及 ProviderEditor.volcengine_service 字段与其读取路径 - 官方新增的两个 remote UI 测试依赖本分支已删除的 remote_ui() 与 rendered_text()/disconnected_app() 助手,在本结构下无法编译(orphan auto-merge): 删除其中被 auto-merge 进来的一个,其覆盖改由前端测试 remote_certificate_details_hide_when_stopped_or_stale_and_warn_without_a_full_fingerprint 承担 - 同时把官方该测试覆盖的行为移植进我们的前端 settings.rs:地址过期(urls_stale)时 不再展示旧网址/配对码;服务在监听但拿不到 64 位十六进制完整指纹时,显式显示 「完整指纹不可用」告警(theme::WARN),而不是静默省略 验证:cargo test --locked 全绿(linux-egui 809 + 其余各 target 0 failed)、 41 个 scripts/*.test.mjs 全 pass、sync-egui-i18n --check 干净(881 keys / 0 added)、 cargo check 无 error。
`1157fe51` 的界面重写把旧 monolith 的 provider 编辑器一起删了,新设置页只留住 「渠道列表 + 新建 + 启停 + 校验 + 删除」,于是 Linux 版既不能录入/修改/删除云服务 凭据,也不能改名、换 provider 类型、重排渠道、选当前渠道 —— 发布流水线第 8 步的 `check-linux-public-surface.ps1` 正是在拦这个(它的注释写明:只有状态、或只有本地 模型捷径的界面不算可用安装路径)。 - 宿主重新接上 Core 的 provider/凭据 API:rename_channel、set_channel_provider_type、 reorder_channels、set_active_provider、set_credential、remove_credential,以及 provider.validate / provider.list_models(模型目录属于 Core)。 - 编辑器草稿放在宿主侧(ProviderEditorForm)并每帧镜像给 view model:重新拉取渠道 列表不会冲掉正在输入的内容;密钥字段只写,打开编辑器不会把已存密钥读进 egui。 - 界面补回:渠道行的编辑/上移下移/换类型/设为当前,以及按 AuthRequirement 渲染的 编辑器(Endpoint/Model/Resource ID/密钥/鉴权模式 + 读取模型 + 保存 + 清空密钥)。 - 顺手修掉「新建渠道」名称框推的是编辑前的值:宿主会把旧值写回,每敲一个字被回灌。 - 新增本地契约测试 provider_surface_contract.rs,把这组 Core 调用钉住,避免下次合并 或清理再把实现删掉(历史上正是这样丢的)。
用户澄清了这个 zip 的用途:不是把安装包再打一层,而是给装不了 deb/rpm 的发行版 手动安装用。所以: - payload 用 `dpkg-deb -x` 解开 deb 得到精确安装树(usr/bin/openless、 usr/lib/*/fcitx5/libopenless.so、addon conf、desktop、metainfo、icon), 并新增硬门禁:散装清单必须与 `dpkg-deb -c` 的文件清单逐项一致(漏文件最难发现)。 - 新增 `openless-all/app/scripts/linux-egui-manual-install.sh`,随包发布为 install.sh:检查 root、先验 SHA256SUMS、按用途给权限铺到 /、用 D-Bus controller Restart 重载 fcitx5(与 deb postinst 一致,不用会卡住的 `fcitx5 -r`),最后打印 重启与卸载提示。 - SHA256SUMS 改为对散装文件 + install.sh 重算;zip 内硬门禁断言不得出现 deb/rpm。 - zip 名自解释:OpenLess-Linux-egui-<tag 或 run>-x86_64-manual.zip;job 名/artifact 名与注释一并从 all-artifacts 改为 manual install,避免语义继续误导。 - deb/rpm 与它们自己的 SHA256SUMS 仍作为独立 release 资产保留(那条 attach 步骤没动)。 - bundle job 补 checkout(脚本随仓库版本走,不内联进 workflow)。
… 升 action 到 node24 版本消掉 node 警告 - 去掉 workflow_call 调用:release-linux-egui.yml 的步骤内联为 release-tauri.yml 里与 build 平级的 linux-egui job,Actions 页面上不再被渲染成嵌套折叠条目 - 同一个 job 内完成 deb/rpm 打包与手动安装 zip 组装(删掉单独的 bundle job) - release 竞态:内联后与 Tauri 三层并发写同一 release,先用 gh release view||create 幂等地建出来(吞掉并发 422),softprops 只做 attach/update - manual zip 语义:散装 usr/ 树 + install.sh + 重算 SHA256SUMS,不含 deb/rpm; deb/rpm 仍作为独立 release 资产 - action 升版(仅这两个发布工作流):checkout v4→v6、setup-node v4→v7、 upload-artifact v4→v7,消除 GitHub action 自身 node20 运行时带来的 DEP0040 punycode / DEP0169 url.parse 弃用警告(用户点名的 node 警告) - 契约测试加锁:断言 Linux 腿必须是内联普通 job、manual zip 必须在同一 job 产出、 两份副本的关键门禁不能漂移
- release-tauri.yml: push.tags 收敛为 'v*';build 与 linux-egui 的 if 不再按 -tauri/-egui 后缀分流(后缀降级为命名约定);Homebrew cask 仍只跟稳定的 -tauri 正式版 (注释写明该边界与影响,避免被顺手放开) - android-apk.yml: 触发从 'v*-tauri' 扩展为 'v*';is_tag_release 判定不再要求 -tauri; OPENLESS_RELEASE_CHANNEL 判定与桌面统一(含 -beta-egui);未签名 debug fallback 语义不变; 注释说明为何 Android 是独立 workflow(另一套 JDK/SDK/Gradle 工具链,塞进 matrix 会让 每步都长满 if)以及它的资产如何落到同一个 release - 顺带把这几个 action 升到 node24 版本(checkout v6 / setup-node v7 / upload-artifact v7), 与发布工作流一致,消掉 action 自身运行时带出的弃用警告 - 契约测试新增:两份工作流都必须对 'v*' 触发、安卓必须挂到同一个 release、 build/linux 两个 job 必须无条件运行、Homebrew 仍锁 -tauri
- 抽出与渲染无关的 tick():原生事件、托盘命令、自动更新检查、心跳日志; eframe 的 update() 与无窗口宿主的 run_headless() 循环共用它,热键消费与 弹窗拉起不再依赖「窗口是否在绘制」(最小化/隐藏/无窗口都照常工作)。 - 关闭键/最小化键:有托盘且没有进行中的会话时切到无窗口宿主。Wayland 下 winit 无法隐藏窗口(set_visible 是空实现),只有窗口进程真的退出,任务栏 与窗口列表里的条目才会消失;会话进行中退回托盘,避免新进程重开后端丢会话。 - 进程形态切换用同可执行文件的新进程 + --takeover:新进程等旧进程释放单实例 锁后接管(不在交接期被转发后直接退出),托盘在接管后重试一次;接管超时降级 为无锁启动,保证托盘/窗口仍可用。 - Core 的 ShowMain/FocusMain 提示在无窗口宿主里不拉起窗口进程(那只是「把已有 窗口推前面」),只有托盘「显示主窗口」才是明确的用户动作。
形态:宿主进程(无窗口,长期存活)持有 Core 后端 / 数据目录 / 单实例锁 / 热键监听 / 托盘 / 弹窗监督器;UI 窗口进程(--ui-client)只渲染。 - 新增 `src/ui/bridge.rs`:unix socket + JSONL 双向协议。快照带单调递增序号, UI 只采纳更大序号(重放/乱序/回退一律丢弃);快照可合并(UI 慢时跳帧, 绝不画过期状态),控制帧永远先于待发快照落盘。 - 关窗 = **只有窗口进程退出**(Wayland 下任务栏条目真的消失);托盘「显示主窗口」 或用户再次启动 = 宿主拉起新窗口进程,宿主 PID 与后端状态原地不动 (实测:宿主 PID 不变、开窗约 50ms,不再重开后端)。 - 时序:先 bind socket 再拉 UI(UI 连不上就直接退出);UI 断连立即作废窗口句柄, 会话/录音/弹窗不受影响;宿主退出先发 Shutdown 再释放单实例锁。 - 删除重启式交接:--headless / --takeover / HandoffMode / spawn_handoff_process / 塌缩 1x1 隐藏 / 最小化改道 / 事件泵后台唤醒线程全部移除。 - `FrontendViewModel` + `FrontendAction` 加最小 serde 集:Lang 按 tag 序列化 (i18n.rs 不允许手改),theme_mode 随快照下发,UI 进程据此配色。 - 事件消费与弹窗拉起改由宿主循环驱动(无窗口 ⇒ 必须线程化),另加 OPENLESS_UI_DEBUG=1 诊断开关记录 UI 侧指针点击与动作。
…+ 浮窗尺寸语义对齐(qa 420×540、preview 640×440 可缩放且抢焦点)
…件序列经 IPC 呈现 + 审批与取消链路) - 新增 PopupKind::LessComputer(--less-computer)与协议版本 4:HostToPopup::LessComputer 携带宿主事件序列(user/tool/compaction/assistant/error)、working、审批与错误; PopupToHost 增加 Submit/Approve/Cancel/Dismiss 四条动作。 - 宿主是事件序列唯一所有者:Core 的 LessComputerEventKind 逐条转成面板条目, 流式增量合并为一条助手条目,终局正文替换它;窗口进程重连即收到完整序列。 - HostAction::ShowLessComputer 不再是空实现;面板尺寸取自共享常量(420×540), 位置与 qa 一致(居中卡片);设置里的开关此前只翻转 coding_agent_enabled,现在 有真实 UI 可看。 - 顺手修正 qa 弹窗视口尺寸的硬编码 520×520(应为共享常量 QA_WINDOW_SIZE=420×540)。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Follow-up before merge